/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package subgradient;

import ilog.concert.IloException;
import java.io.File;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale;
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Guillaume
 */
public class SubGradient {
    
     private DecimalFormat dF; //permet de tronquer les chiffres

    private Scanner scan;
    private static final Locale LOCALE = Locale.US;
    
    
    private PrintWriter fileResult;
    private PrintWriter fileStatResult;
    private String[] nameFiles;
    
    private int nbNotOptimals; 
    
    
    private HashMap<String,ArrayList<String>> kindExperience;   //Hashmap pour réorganiser les fichiers de données
    private Time time;
    
    
    /**
     * Class for filtering files name extensions.
    */
    private class Filter implements FilenameFilter
    {
        @Override
        public boolean accept(File rep, String fichier) {

            if (fichier.endsWith(".txt") || fichier.endsWith(".class")){
                return true;
            }
            return false;
        }
    }
    
    public SubGradient(int nb){
        this.dF = new DecimalFormat();
        dF.setMaximumFractionDigits(nb);
        this.nbNotOptimals = 0;
    }
    
    public void launchSimulation(String path, double capSack) throws IloException{
        
        File f = new File(path);
        f.mkdirs();
        
        // Lists all files which end by ".txt"
        nameFiles = new java.io.File(path + ".").list(new Filter());
        Arrays.sort(nameFiles);
        
        kindExperience = new HashMap<String,ArrayList<String>>();
        
        for (int i = 0; i < nameFiles.length; i++) {
            
            //we don't want to map files which start with "Résult" and "Stat" --> they aren't data files.
            if(!nameFiles[i].startsWith("Résult")
                    && !nameFiles[i].startsWith("Stat")){
             
                scan = new Scanner(nameFiles[i]);
                scan.useLocale(LOCALE);
                scan.useDelimiter("_| "); //délimiteur = "_" ou " "
                
                String key = "PARAMETRES :\tALPHA = " + nextDouble() +
                                " \t NbOBJETS = " + nextInt() +
                                " \t CAPACITeSAC = " + nextDouble(); //ATTENTION : pour assurer l'unicité de la clé
                                                                                   // Il faut s'assurer que la combinaison des paramètres
                                                                                    //donne des chaines uniques (ici c'est le cas car alpha != W partout)
                
                scan.useDelimiter("v|\\."); //on change le délimiteur pour la fin de la chaine... (le numéro de version.)
                
                int version = nextInt();
                
                //Si la hashmap ne contient pas la clé, on la rajoute...
                if(!kindExperience.containsKey(key)){
                    
                    kindExperience.put(key, new ArrayList<>());
                }
                
                //On met l'expérience à la place quelle doit être dans l'arrayList...
                while(kindExperience.get(key).size() <= version){
                        kindExperience.get(key).add("");
                }
                kindExperience.get(key).set(version, nameFiles[i]);
                
                
                
            }
        }
        
        //Maintenant que les fichiers de données sont triés, on peut lancer la simulation
        int nbSimulations = kindExperience.get(kindExperience.keySet().iterator().next()).size();
        
        fileResult = initOutput("Resultats",fileResult,"Fichier contenant les résultats de chaque expérience");
        fileStatResult = initOutput("StatsResults", fileStatResult,"Résultats des statistiques obtenues sur des séries de " + nbSimulations + " simulations");
        
        fileResult.flush();
        fileStatResult.flush();
        
        ArrayList<Stats> listStats = new ArrayList<>();
            //On trie un peu la liste des clé pour que ce ne soit pas trop moche.
        String[] str = kindExperience.keySet().toArray(new String[kindExperience.keySet().size()]);
        Arrays.sort(str);
        
        int serie = 0;
        
        Time timer = new Time();
        
        for(String s: str){
            
            System.out.println("série numéro : " + serie++);
            nbNotOptimals = 0;
            
            Stats stat = new Stats();
            
            for (int i = 0; i < kindExperience.get(s).size(); i++) {
                
                String fileName = kindExperience.get(s).get(i);
                
                fileResult.println(path + fileName);
                
                DataProblem dat = new DataProblem(path + fileName, capSack);
                dat.readFile();
                SubGradientSolver problem = new SubGradientSolver();
                
                
                Time timeSolve = new Time();
                Solution sol = problem.solve(dat);
                fileResult.println("  Temps : " + timeSolve.timeElapsed());
                fileResult.println(sol);
                fileResult.println("  Z = " + dF.format(sol.profit(dat)));
                fileResult.println("  Capacité sac restante : " + dF.format(capSack-sol.weight(dat)));
                if(problem.isOptimal){
                    fileResult.println("  Solution Optimale : PROBABLE");
                }else{
                    fileResult.println("  Solution Optimale : NON");
                    nbNotOptimals++;
                }
                fileResult.println("");
                fileResult.println("");
                fileResult.flush();
                
                
                stat.setT((timeSolve.getLastSavedTime() / 1000000));
                stat.setZ(sol.profit(dat));
                stat.setC(capSack-sol.weight(dat));
                
            }
            
            
            
            fileStatResult.println("");
            fileStatResult.println("");
            
            fileStatResult.println(s);

            fileStatResult.println("  Temps Moyen: " + new Time((long)stat.gettMoy()*1000000l)
                                + "   (Min = " + new Time((long)stat.getTmin()*1000000l) + ", "
                                +     "Max = " + new Time(stat.getTmax()*1000000l) + ")"
                                + "  Ecart type (ref = ms) = " + (Math.sqrt(stat.gettVar())));

            fileStatResult.println("  Z Moyen: " + dF.format(stat.getzMoy())
                                + "   (Min = " + dF.format(stat.getZmin()) + ", "
                                +     "Max = " + dF.format(stat.getZmax()) + ")"
                                + "  Ecart type = " + dF.format(Math.sqrt(stat.getzVar())));

            fileStatResult.println("  Capacité sac restante moyenne: " 
                                + dF.format(stat.getcMoy())
                                + "   (Min = " + dF.format(stat.getCmin()) + ", "
                                +     "Max = " + dF.format(stat.getCmax()) + ")"
                                + "  Ecart type = " + dF.format(Math.sqrt(stat.getcVar())));
            fileStatResult.println("  Nombre de solutions non optimales: " + nbNotOptimals);

            fileStatResult.flush();
        }
        
        fileResult.println("");
        fileResult.println("");
        fileResult.println("");
        fileResult.println("Temps total de calcul :");
        fileResult.println(timer.timeElapsed());
        fileResult.println("==================================================");
        fileResult.flush();
        
        fileStatResult.println("");
        fileStatResult.println("");
        fileStatResult.println("");
        fileStatResult.println("Temps total de calcul :");
        fileStatResult.println(new Time(timer.getLastSavedTime()));
        fileStatResult.println("===============================================");
        fileStatResult.flush();
        
        fileResult.close();
        fileStatResult.close();
    }
    
    /**
     * gets the next int in scanner.
     * @return the next int in scanner
     * @throws NoSuchElementException if there isn't next int in scan
     */
    private int nextInt() throws NoSuchElementException{
        while(scan.hasNext()){
            if (scan.hasNextInt()){
                return scan.nextInt();
            }else scan.next();
        }
        throw new NoSuchElementException("There isn't any next integer in file");
    }
    
    /**
     * gets the next double in scanner.
     * @return the next double in scanner
     * @throws NoSuchElementException if there isn't next int in scan
     */
    private double nextDouble() throws NoSuchElementException{
        while(scan.hasNext()){
            if (scan.hasNextDouble()){
                return scan.nextDouble();
            }else scan.next();
        }
        throw new NoSuchElementException("There isn't any next integer in file");
    }
    
    
    private PrintWriter initOutput(String nameFileResult, PrintWriter file, String intro){
        try {
            file = null;
            String path2 = System.getProperty("user.dir")+"//Résultats//";
            File f = new File(path2);
            f.mkdirs();
            file = new PrintWriter(new FileWriter(path2 + nameFileResult +".txt"));
            file.println(intro);
            file.println("====================================================");
            file.println("Ordinateur\t \t : Z97");
            file.println("Processeur\t \t : i7 4790k @ 4.4Ghz");
            file.println("Mémoire vive\t \t : 16GB");
            file.println("OS \t \t \t : VM Ubuntu 14.04 émulée sur Windows 7");
            file.println("");
            file.println("====================================================");
            file.println("");
            file.println("");
            file.flush();
        } catch (IOException ex) {
            Logger.getLogger(SubGradient.class.getName()).log(Level.SEVERE, null, ex);
        }
        
        return file;
    }
    
    
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws IloException {
        SubGradient subgrad = new SubGradient(3);
        subgrad.launchSimulation("/home/guigz/Bureau/SFA/M2/S1/Programmation en variables entières/Projet/SubGradient/SubGradient/DATA/",10000);
    }
    
}
